﻿using System;
using System.Collections.Generic;
using System.Data.Common;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using FreeSql.Internal.Model;
using LightLog.Model.Config;
using LightLog.IService;
using LightLog.Service;
using FreeSqlExtensions;
using LightLog.Entity;
using LightLog.Framework.Extensions;
using LightLog.Model.DTO;
using LightLog.Model.Input;
using Mapster;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using JwtHelper = LightLog.Service.JwtHelper;
using Serilog;

namespace LightLog.Service
{
    public class UserService : BaseService, IUserService
    {
        private readonly IFreeSql _fsql;
        private readonly IHttpContextAccessor _accessor;

        public UserService(IFreeSql fsql, IHttpContextAccessor accessor)
        {
            _fsql = fsql;
            _accessor = accessor;
        }

        public async Task<List<UserDTO>> GetListAsync(UserListInput input)
        {
            return await _fsql.Select<Entity.User>()
                .WhereIf(!string.IsNullOrEmpty(input.UserName), p => p.UserName.Contains(input.UserName))
                .WhereIf(input.HaveAdmin == 0, p => p.IsAdmin == false)
                .WhereIf(input.HaveAdmin == 1, p => p.IsAdmin == true)
                .ToListAsync(p => new UserDTO()
                {
                    ProjectList = _fsql.Select<Entity.Project>()
                        .Where(pj => _fsql.Select<Entity.UserProject>().Where(up => up.ProjectID == pj.ID && up.UserID == p.ID).Any())
                        .ToList(p => new ProjectDTO())
                });
        }

        public async Task<UserDTO> GetUserAsync(long userid)
        {
            return await _fsql.Select<Entity.User>()
                .Where(p => p.ID == userid)
                .ToOneAsync(p => new UserDTO()
                {
                    ProjectList = _fsql.Select<Entity.Project>()
                        .Where(pj => _fsql.Select<Entity.UserProject>().Where(up => up.ProjectID == pj.ID && up.UserID == p.ID).Any())
                        .ToList(p => new ProjectDTO())
                });
        }

        public async Task<bool> GetIsAdminAsync(long userid)
        {
            return await _fsql.Select<Entity.User>().Where(p => p.ID == userid).ToOneAsync(p => p.IsAdmin);
        }

        public async Task<(long, string)> CreateUserAsync(UserInput input)
        {
            //验证用户名重复 
            bool haveUser = await _fsql.Select<Entity.User>().Where(p => p.UserName == input.UserName).AnyAsync();
            if (haveUser)
            {
                return (0, "用户名重复!");
            }

            var user = input.Adapt<Entity.User>();
            user.Pwd = LightLog.Framework.Security.GetMd5Pwd(user.Pwd);

            if (await _fsql.Insert(user).ExecuteAffrowsAsync() > 0)
            {
                return (user.ID, "");
            }
            else
            {
                return (0, "创建用户失败!");
            }
        }

        public async Task<string> UpdateUserAsync(UserUpdateInput input)
        {
            //验证用户名重复 
            bool haveUser = await _fsql.Select<Entity.User>().Where(p => p.UserName == input.UserName && p.ID != input.UserId).AnyAsync();
            if (haveUser)
            {
                return "用户名重复!";
            }

            var user = await _fsql.Select<Entity.User>().Where(p => p.ID == input.UserId).ToOneAsync();
            string oldPwd = user.Pwd;
            user = input.Adapt<Entity.User>();
            user.Pwd = !string.IsNullOrEmpty(input.Pwd) ? LightLog.Framework.Security.GetMd5Pwd(user.Pwd) : oldPwd;

            if (await _fsql.Update<Entity.User>().SetSource(user).ExecuteAffrowsAsync() > 0)
            {
                return "";
            }
            else
            {
                return "创建用户失败!";
            }
        }

        public async Task<bool> SetUserProjectAsync(List<UserProjectDTO> list, long userId)
        {
            var userProjectList = list.Adapt<List<Entity.UserProject>>();

            using var conn = await _fsql.Ado.MasterPool.GetAsync();
            await using var transaction = await conn.Value.BeginTransactionAsync();
            try
            {
                await _fsql.Delete<Entity.UserProject>().WithTransaction(transaction).Where(p => p.UserID == userId).ExecuteAffrowsAsync();

                if (!list.IsNullOrEmpty())
                    await _fsql.Insert(userProjectList).WithTransaction(transaction).NoneParameter().ExecuteAffrowsAsync();

                await transaction.CommitAsync(); //提交事务
                return true;
            }
            catch (Exception e)
            {
                Log.Logger.Error(e.GetExceptionMsg());
                await transaction.RollbackAsync(); //回滚事务
                return false;
            }
        }

        public async Task<bool> DeleteUserProjectByUseridAsync(long userId)
        {
            return await _fsql.Delete<Entity.UserProject>().Where(p => p.UserID == userId).ExecuteAffrowsAsync() > 0;
        }

        public async Task<bool> ChangePwdAsync(UserChangeInput input)
        {
            var userid = GetUserIDByToken();
            var oldPwd=LightLog.Framework.Security.GetMd5Pwd(input.OldPwd);
            var newPwd = LightLog.Framework.Security.GetMd5Pwd(input.NewPwd);
            return await _fsql.Select<Entity.User>()
                .Where(p => p.ID == userid && p.Pwd == oldPwd)
                .ToUpdate()
                .Set(p => p.Pwd == newPwd).ExecuteAffrowsAsync() > 0;
        }

        public long GetUserIDByToken()
        {
            var token = _accessor.HttpContext.Request.Headers["Authorization"].ToString().Split(' ')[1];
            JwtSecurityToken jwtToken = new JwtSecurityTokenHandler().ReadJwtToken(token);
            return Convert.ToInt64(jwtToken.Payload[ClaimName.UserId].ToString());
        }
    }
}
